﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NP.BPMReportPlatform.DBHelper;
using NP.BPMReportPlatform.MaterialMasterData.Dtos;
using System.Text.Json.Nodes;
using Newtonsoft.Json;
using NP.BPMReportPlatform.BPMPlatform;
using NP.BPMReportPlatform.Entities.BPM_Business.LCZX;
using NP.BPMReportPlatform.Entities.BPM_Engine;
using NP.BPMReportPlatform.MaterialMasterData.Dto;
using NP.BPMReportPlatform.Utilities;
using NP.BPMReportPlatform.Utils;
using Serilog;
using SqlSugar;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Volo.Abp.Application.Dtos;
using NP.BPMReportPlatform.Entities.BPM_Business;
using Microsoft.Extensions.Configuration;
using RazorEngine.Compilation.ImpromptuInterface;

namespace NP.BPMReportPlatform.MaterialMasterData
{
    public class LCZXRZXQGLService : BPMReportPlatformAppService, ILCZXRZXQGLService
    {
        private readonly SqlSugarClient _db;
        private readonly SqlSugarClient _dbEngine;
        private readonly ILogger _logger;
        private readonly IBPMUtilsAppService _bPMUtilsApp;
        private readonly IBPMPlatformAppService _iBPMPlatformApp;
        private readonly IConfiguration _configuration;

        public LCZXRZXQGLService(ISqlSugarAppService service, ILogger logger, IBPMUtilsAppService bPMUtilsApp,
            IBPMPlatformAppService bPMPlatformApp, IConfiguration configuration)
        {
            _db = service.GetBusinessInstance();
            _dbEngine = service.GetEngineInstance();
            _logger = logger;
            _bPMUtilsApp = bPMUtilsApp;
            _iBPMPlatformApp = bPMPlatformApp;
            _configuration = configuration;
        }

        public async Task InsertConfig(LCZXRZXQGLConfigInputDto model)
        {
            model.Id = Guid.NewGuid();
            var convertModel = ObjectMapper.Map<LCZXRZXQGLConfigInputDto, LCZXRZXQGLConfig>(model);
            convertModel.AddTime = DateTime.Now;
            await _db.Insertable(convertModel).ExecuteCommandAsync();
        }

        public async Task UpdateConfig(LCZXRZXQGLConfigInputDto model)
        {
            var convertModel = ObjectMapper.Map<LCZXRZXQGLConfigInputDto, LCZXRZXQGLConfig>(model);
            convertModel.UpdateTime = DateTime.Now;
            var entity = _db.Queryable<LCZXRZXQGLConfig>().First(x => x.Id == model.Id);
            if (entity != null)
            {
                convertModel.AddTime = entity.AddTime == null ? convertModel.UpdateTime : entity.AddTime;
            }
            await _db.Updateable(convertModel).ExecuteCommandAsync();
        }

        public async Task DeleteConfig(Guid id)
        {
            var entity = await _db.Queryable<LCZXRZXQGLConfig>().FirstAsync(x => x.Id == id);
            entity.InUse = false;
            await _db.Updateable(entity).ExecuteCommandAsync();
            return;
        }

        public async Task<List<LCZXRZXQGLConfigInputDto>> GetConfig(LCZXRZXQGLConfigInputDto input)
        {
            var models = await _db.Queryable<LCZXRZXQGLConfig>()
                .WhereIF(input.InUseSearch != null, x => x.InUse == input.InUseSearch)
                .WhereIF(!string.IsNullOrEmpty(input.NipponCertification), x => x.NipponCertification.Contains(input.NipponCertification))
                .WhereIF(!string.IsNullOrEmpty(input.CertificateType), x => x.CertificateType.Contains(input.CertificateType) ||
                    x.SubCertificateType.Contains(input.SubCertificateType))
                .WhereIF(!string.IsNullOrEmpty(input.TypeOfWork), x => x.TypeOfWork.Contains(input.TypeOfWork))
                .OrderBy(x => new { x.InUse, x.CertificateType, x.SubCertificateType, x.NipponCertification }, OrderByType.Desc).ToListAsync();
            if (models.Count == 0)
            {
                return new List<LCZXRZXQGLConfigInputDto>();
            }

            return ObjectMapper.Map<List<LCZXRZXQGLConfig>, List<LCZXRZXQGLConfigInputDto>>(models);
        }


        #region 配置子表

        public async Task<PagedResultDto<LCZXRZXQGLConfigChild>> GetChildConfigs(Guid configId, int PageIndex = 1, int PageSize = 10)
        {
            var data = await _db.Queryable<LCZXRZXQGLConfigChild>().Where(x => x.ConfigId.Equals(configId))
                .OrderBy(x => new { x.Name, x.Key, x.Value }).ToPageListAsync(PageIndex, PageSize);
            var totalCount = await _db.Queryable<LCZXRZXQGLConfigChild>().Where(x => x.ConfigId.Equals(configId)).CountAsync();
            return new PagedResultDto<LCZXRZXQGLConfigChild>()
            {
                TotalCount = totalCount,
                Items = data
            };
        }

        public async Task EditChildConfig(LCZXRZXQGLConfigChild model)
        {
            if (model == null)
            {
                throw new Exception("请输入有效数据");
            }
            if (model.ConfigId == null || model.ConfigId == Guid.Empty)
            {
                throw new Exception("未找到父级配置");
            }
            if (model.Id == null || model.Id == Guid.Empty)
            {
                model.Id = Guid.NewGuid();
                await _db.Insertable(model).ExecuteCommandAsync();
            }
            else 
            {
                var entity = await _db.Queryable<LCZXRZXQGLConfigChild>().FirstAsync(x => x.Id == model.Id);
                if (entity == null)
                {
                    throw new Exception("未找到有效数据");
                }
                entity.Effect = model.Effect;
                entity.ConfigId = model.ConfigId;
                entity.Dept = model.Dept;
                entity.Grade = model.Grade;
                entity.LCCertificateTemplate = model.LCCertificateTemplate;
                entity.StartNumber = model.StartNumber;
                entity.Key = model.Key;
                entity.Value = model.Value;
                entity.Name = model.Name;
                await _db.Updateable(entity).ExecuteCommandAsync();
            }
        }

        public async Task DeleteChildConfig(Guid id)
        {
            var entity = await _db.Queryable<LCZXRZXQGLConfigChild>().FirstAsync(x => x.Id == id);
            if (entity == null)
            {
                throw new Exception("未找到有效数据");
            }
            else
            {
                await _db.Deleteable(entity).ExecuteCommandAsync();
            }
        }

        #endregion

        #region 证书数据维护

        public async Task<PagedResultDto<LCZXRZXQGLDetail>> GetCertificateData(GetCertificateDataInput input)
        {
            RefAsync<int> totalCount = 0;
            var datas = await _db.Queryable<LCZXRZXQGLDetail, BusinessProcessesNew>(
                (x, b) => new JoinQueryInfos(JoinType.Left, x.InstanceNumber.Equals(b.InstanceId)))
                .Where((x, b) =>
                    (x.InstanceNumber.Equals("999999999999") ||
                    (!x.InstanceNumber.Equals("999999999999") &&
                    (b.ProcessStatusCode.Equals("approved") || b.ProcessStatusCode.Equals("processing")))) && x.IsGenerateNumber)
                .WhereIF(!string.IsNullOrWhiteSpace(input.StudentName), x => x.StudentName.Equals(input.StudentName))
                .WhereIF(!string.IsNullOrWhiteSpace(input.IdCardNumber), x => x.IdCardNumber.Equals(input.IdCardNumber))
                .WhereIF(!string.IsNullOrWhiteSpace(input.CertificateNumber), x => x.CertificateNumber.Equals(input.CertificateNumber))
                .WhereIF(!string.IsNullOrWhiteSpace(input.CertificateName), x => x.CertificateName.Contains(input.CertificateName))
                .WhereIF(!string.IsNullOrWhiteSpace(input.CertificateType), x => x.CertificateType.Contains(input.CertificateType))
                .Select(x => x).MergeTable().OrderBy(x => x.InstanceNumber == "999999999999" ? "" : x.InstanceNumber, OrderByType.Desc)
                .ToPageListAsync(input.PageIndex, input.PageSize, totalCount);
            datas.ForEach(x =>
            {
                x.InstanceNumber = x.InstanceNumber == "999999999999" ? "" : x.InstanceNumber;
                if (!string.IsNullOrEmpty(x.InstanceNumber))
                {
                    x.Url = string.Format(_configuration["BPM:NoAuthPCProcessUrl"], x.InstanceNumber);
                }

                if (!string.IsNullOrEmpty(x.AreaString))
                {
                    var areaArr = x.AreaString.Split(new char[] { ',', '，', ';', '；' });
                    x.Province = areaArr.Length >= 1 ? areaArr[0] : "";
                    x.City = areaArr.Length >= 2 ? areaArr[1] : "";
                    x.Area = areaArr.Length >= 3 ? areaArr[2] : "";
                }
            });
            return new PagedResultDto<LCZXRZXQGLDetail>()
            {
                TotalCount = totalCount,
                Items = datas
            };
        }

        public async Task<string> UpdateCertificateData(UpdateCertificateDataInput input)
        {
            var data = await _db.Queryable<LCZXRZXQGLDetail>().FirstAsync(x => x.Id == input.Id);
            if (data == null)
            {
                return "数据未找到";
            }

            if(string.IsNullOrWhiteSpace(input.StudentName) || string.IsNullOrWhiteSpace(input.IdCardNumber) ||
                string.IsNullOrWhiteSpace(input.Province) || string.IsNullOrWhiteSpace(input.City) ||
                string.IsNullOrWhiteSpace(input.Area) || string.IsNullOrWhiteSpace(input.ContractDetail))
            {
                return "缺少入参";
            }

            var oldData = JsonConvert.SerializeObject(data);

            data.StudentName = input.StudentName;
            data.IdCardNumber = input.IdCardNumber;
            data.CareerStartTime = input.CareerStartTime;
            data.Province = input.Province;
            data.City = input.City;
            data.Area = input.Area;
            data.AreaString = $"{input.Province},{input.City},{input.Area}";
            data.ContractDetail = input.ContractDetail;
            data.TheoreticalScore = input.TheoreticalScore;
            data.PracticalScore = input.PracticalScore;
            data.IsPublic = input.IsPublic;
            var flag = await _db.Updateable(data).ExecuteCommandHasChangeAsync();
            if (flag)
            {
                var needSync = data.CertificateNumber != "999999999999" && !string.IsNullOrWhiteSpace(data.CertificateNumber);
                //记录修改历史表
                var record = new LCZXRZXQGLDataChangeRecord
                {
                    Id = Guid.NewGuid(),
                    InstanceNumber = data.InstanceNumber,
                    AddTime = DateTime.Now,
                    AddUser = CurrentUser.UserName,
                    NewData = JsonConvert.SerializeObject(data),
                    OldData = oldData,
                    IdCardNumber = data.IdCardNumber,
                    StudentName = data.StudentName,
                    CertificateNumber = data.CertificateNumber,
                    CertificateType = data.CertificateType,
                    CertificateName = data.CertificateName,
                    CareerStartTime = data.CareerStartTime,
                    IsSyncSuccess = !needSync,
                };
                if (needSync)
                {
                    try
                    {
                        var instance = await _dbEngine.Queryable<Instances>().FirstAsync(x => x.Number == data.InstanceNumber);
                        if (instance != null)
                        {
                            var instanceParams = await _dbEngine.Queryable<InstanceParams>()
                                .FirstAsync(x => x.InstanceId == instance.InstanceId && x.Key == "lineData");
                            if (instanceParams != null)
                            {
                                var oldParam = JsonConvert.DeserializeObject<LCZXRZXQGLDetail>(oldData);
                                var options = new JsonSerializerOptions
                                {
                                    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) // 设置编码范围为所有 Unicode 字符
                                };
                                var jsonNode = System.Text.Json.JsonSerializer.Deserialize<JsonNode>(instanceParams.Value, options);
                                var jObjectList = jsonNode.AsArray();
                                var haveChange = false;
                                foreach (var item in jObjectList)
                                {
                                    if (item["studentName"].GetValue<string>() == oldParam.StudentName &&
                                        item["idCardNumber"].GetValue<string>() == oldParam.IdCardNumber &&
                                        item["certificateType"].GetValue<string>() == oldParam.CertificateType &&
                                        item["certificateName"].GetValue<string>() == oldParam.CertificateName)
                                    {
                                        haveChange = true;
                                        item["studentName"] = data.StudentName;
                                        item["idCardNumber"] = data.IdCardNumber;
                                        item["careerStartTime"] = data.CareerStartTime;
                                        var areas = new List<string>
                                        {
                                            data.Province,
                                            data.City,
                                            data.Area
                                        };
                                        item["area"] = areas.ToJsonNode();
                                        item["theoreticalScore"] = data.TheoreticalScore;
                                        item["practicalScore"] = data.PracticalScore;
                                        item["contractDetail"] = data.ContractDetail;
                                    }
                                }
                                var options1 = new JsonSerializerOptions
                                {
                                    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                                };
                                var updatedData = System.Text.Json.JsonSerializer.Serialize(jObjectList, options1);
                                instanceParams.Value = updatedData;

                                if (haveChange)
                                {
                                    var flag1 = await _dbEngine.Updateable(instanceParams).ExecuteCommandHasChangeAsync();
                                    if (flag1)
                                    {
                                        record.IsSyncSuccess = true;
                                    }
                                    else
                                    {
                                        record.IsSyncSuccess = false;
                                        record.SyncResult = "Update Failed";
                                    }
                                }
                                else
                                {
                                    record.IsSyncSuccess = false;
                                    record.SyncResult = "Certificate Data Not Found";
                                }
                            }
                            else
                            {
                                record.IsSyncSuccess = false;
                                record.SyncResult = "Instance Params Data Not Found";
                            }
                        }
                        else
                        {
                            record.IsSyncSuccess = false;
                            record.SyncResult = "Instance Data Not Found";
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.Error("UpdateCertificateData:" + ex.Message);
                        record.IsSyncSuccess = false;
                        record.SyncResult = "Error:" + string.Concat(ex.Message.Take(800));
                    }
                }

                await _db.Insertable(record).ExecuteCommandAsync();
            }
            return flag ? "保存成功" : "保存失败";
        }

        #endregion
    }
}